#ifdef sm
struct {
	uint8_t w, h;
	// w * h
	// calculated in ms_new()
	uint16_t size;
	// number of mines
	uint8_t n;
	// number of remaining mines
	// 0 = win
	// 255 = lose (draw everything revealed)
	uint8_t r;
	// field[y * w + x]
	// 0~8 = revealed empty square
	// 16~24 = precalculated empty square
	// 32~40 = wrong flag
	// 255 = hidden mine
	// 239 = correct flag
	// bit 4 = draw as an unrevealed square
	// bit 5 = draw as a flagged square
	uint8_t a[480];
	uint8_t x, y; // cursor
	uint8_t ox, oy; // scroll
} ms;
#else
void ms_new() {
	register uint8_t x, y, t;
	register uint16_t i, j;
	sm.ms.size = sm.ms.w * sm.ms.h;
	sm.ms.r = sm.ms.n;
	// populate the field
	for (i = sm.ms.size; i--; ) sm.ms.a[i] = i < sm.ms.n ? 255 : 0;
	// shuffle the mines and empty squares
	for (i = sm.ms.size; i--; ) {
		j = vcrand() % (i + 1);
		x = sm.ms.a[i];
		sm.ms.a[i] = sm.ms.a[j];
		sm.ms.a[j] = x;
	}
	// calculate numbers in the squares
	for (x = 0; x < sm.ms.w; x++) {
		for (y = 0; y < sm.ms.h; y++) {
			i = y * sm.ms.w + x;
			if (!sm.ms.a[i]) {
				// not a mine
				t = 0;
				if (y > 0) {
					if (sm.ms.a[i - sm.ms.w] == 255) t++;
					if (x > 0 && sm.ms.a[i - sm.ms.w - 1] == 255) t++;
					if (x < sm.ms.w - 1 && sm.ms.a[i - sm.ms.w + 1] == 255) t++;
				}
				if (x > 0 && sm.ms.a[i - 1] == 255) t++;
				if (x < sm.ms.w - 1 && sm.ms.a[i+ 1] == 255) t++;
				if (y < sm.ms.h - 1) {
					if (sm.ms.a[i + sm.ms.w] == 255) t++;
					if (x > 0 && sm.ms.a[i + sm.ms.w - 1] == 255) t++;
					if (x < sm.ms.w - 1 && sm.ms.a[i + sm.ms.w + 1] == 255) t++;
				}
				sm.ms.a[i] = t | 16;
			}
		}
	}
}

void ms_scroll() {
	if (sm.ms.x < sm.ms.ox) {
		sm.ms.ox = sm.ms.x;
	} else if (sm.ms.x > sm.ms.ox + 13) {
		sm.ms.ox = sm.ms.x - 13;
	}
	if (sm.ms.y < sm.ms.oy) {
		sm.ms.oy = sm.ms.y;
	} else if (sm.ms.y > sm.ms.oy + 7) {
		sm.ms.oy = sm.ms.y - 7;
	}
}

void ms_redraw() {
	register uint8_t x, y, i, a;
	for (i = 0; i < 64; i++) {
		fill_scanline((i + 1) & 7 ? 0x8080 : 0xffff);
		dm.g.scanline[7] = 0;
		y = sm.ms.oy + (i >> 3);
		switch (i & 7) {
		case 1: case 2: case 3: case 4: case 5:
			for (x = 0; x < 14; x++) {
				a = sm.ms.a[(uint16_t) y * sm.ms.w + sm.ms.ox + x];
				if (sm.ms.r == 255 && a == 255) {
					draw_part((x << 3) + 1, 35, 136 + (i & 7), 5);
				} else if (a & 16) {
					draw_part((x << 3) + 1, 40, 136 + (i & 7), 5);
				} else if (a & 32) {
					draw_part((x << 3) + 2, 45, 136 + (i & 7), 3);
				} else if (a) {
					draw_part((x << 3) + 2, 3 * a, 141 + (i & 7), 3);
				}
			}
		}
		if (sm.ms.y == y) {
			x = sm.ms.x - sm.ms.ox;
			if (x < 14) {
				switch (i & 7) {
				case 1: case 2: case 3: case 4: case 5:
					dm.g.scanline[x >> 1] |= 0x41 << ((x & 1) << 3);
					break;
				default:
					draw_part(x << 3, 0, 255, 8);
				}
			}
		}
		draw_scanline(i);
	}
}

void ms_click() {
	if (sm.ms.a[sm.ms.y * sm.ms.w + sm.ms.x] & 16) {
		if (sm.ms.a[sm.ms.y * sm.ms.w + sm.ms.x] == 255) {
			sm.ms.r = 255;
		} else if (sm.ms.a[sm.ms.y * sm.ms.w + sm.ms.x]) {
			sm.ms.a[sm.ms.y * sm.ms.w + sm.ms.x] &= 15;
		} else {
			// to expand
		}
		ms_redraw();
	}
}

void ms_flag() {
	if (sm.ms.a[sm.ms.y * sm.ms.w + sm.ms.x] & 192) {
		sm.ms.a[sm.ms.y * sm.ms.w + sm.ms.x] ^= 16;
		if (sm.ms.a[sm.ms.y * sm.ms.w + sm.ms.x] & 16) {
			sm.ms.r++;
		} else {
			sm.ms.r--;
		}
		ms_redraw();
	}
}

void ms_on_keydown(uint8_t key) {
	if (sm.ms.r == 255) {
	} else if (sm.ms.r) {
		switch (key) {
		case 5:
			ms_click();
			break;
		case 6:
			ms_flag();
			break;
		}
	} else {
	}
	switch (key) {
	case 0:
		if (sm.ms.x > 0) sm.ms.x--;
		ms_scroll();
		ms_redraw();
		break;
	case 1:
		if (sm.ms.y < sm.ms.h - 1) sm.ms.y++;
		ms_scroll();
		ms_redraw();
		break;
	case 2:
		if (sm.ms.y > 0) sm.ms.y--;
		ms_scroll();
		ms_redraw();
		break;
	case 3:
		if (sm.ms.x < sm.ms.w - 1) sm.ms.x++;
		ms_scroll();
		ms_redraw();
		break;
	}
	lcd_flush();
}

void ms_on_init(void) {
	lcd_clear_button_text();
	lcd_set_button_text(0, L"\u2190");
	lcd_set_button_text(1, L"\u2193");
	lcd_set_button_text(2, L"\u2191");
	lcd_set_button_text(3, L"\u2192");
	lcd_set_button_text(5, L"\u0391"); // L
	lcd_set_button_text(6, L"\u0392"); // R
	lcd_set_button_text(9, L"N");
	on_keydown = ms_on_keydown;
	sm.ms.w = 30;
	sm.ms.h = 16;
	sm.ms.n = 99;
	ms_new();
	ms_redraw();
	lcd_flush();
}
#endif
